let i = 0;
class MyPromise {
  constructor(executor) {
    i++;
    // 初始化值
    this.initValue()
    //初始化this指向
    this.initBind()
    // Promise中有throw的话，就相当于执行了reject
    try {
      executor(this.resolve, this.reject)
    } catch (e) {
      this.reject(e)
    }
  }

  initBind() {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }

  initValue() {
    this.i = i;
    this.PromiseState = 'pedding'
    this.PromiseResult = null

    this.onFulfilledCallbacks = [] // 保存成功回调
    this.onRejectedCallbacks = [] // 保存失败回调
  }

  resolve(value) {
    if (this.PromiseState !== 'pedding') return
    this.PromiseState = 'fulfilled'
    this.PromiseResult = value
    // 执行保存的成功回调
    while(this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.PromiseResult)
    }
  }

  reject(reason) {
    if (this.PromiseState !== 'pedding') return
    this.PromiseState = 'rejected'
    this.PromiseResult = reason
    // 执行保存的失败回调
    while(this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.PromiseResult)
    }
  }

  then(onFulfilled, onRejected) {
    // 接收两个回调 onFulfilled, onRejected

    // 参数校验，确保一定是函数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
    var thenPromise = new MyPromise((resolve, reject) => {
      const resolvePromise = (cb) => {
        setTimeout(() => {
          try {
            const x = cb(this.PromiseResult)
            if (x === thenPromise && x) {
              throw new Error('不能返回自身。。。')
            }
            if (x instanceof MyPromise) {
              // 如果返回值是Promise
              // 如果返回值是promise对象，返回值为成功，新promise就是成功
              // 如果返回值是promise对象，返回值为失败，新promise就是失败
              // 谁知道返回的promise是失败成功？只有then知道
              x.then(resolve, reject)
            } else {
              // 非Promise就直接成功
              resolve(x)
            }
          } catch (e) {
            reject(e)
            throw new Error(err)
          }
        }, 0)
      }

      if (this.PromiseState === 'fulfilled') {
        resolvePromise(onFulfilled)
      } else if (this.PromiseState === 'rejected') {
        resolvePromise(onRejected)
      } else if (this.PromiseState === 'pedding') {
        this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
        this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected))
      }
    })

    return thenPromise
  }

  static all(promises) {
    const result = []
    let count = 0
    return new MyPromise((resolve, reject) => {
      const addData = (index, value) => {
        result[index] = value
        count++
        if (count === promises.length) resolve(resolve)
      }

      promises.forEach((promise, index) => {
        if (promise instanceof MyPromise) {
          promise.then(res => addData(index, res), err => reject(err))
        } else {
          addData(index, promise)
        }
      })
    })
  }

  static race(promises) {
    return new Promise((resolve, reject) => {
      promises.forEach(promise => {
        if (promise instanceof MyPromise) {
          promise.then(res => resolve(res), err => reject(err))
        } else {
          resolve(promise)
        }
      })
    })
  }

  static allSettled(promises) {
    return new Promise((resolve, reject) => {
      const res = []
      let count = 0;

      const addData = (status, val, i) => {
        res[i] = { status, val }
        count++
        if (count === promises.length) {
          resolve(res)
        }
      }
      promises.forEach((promise, index) => {
        if (promise instanceof MyPromise) {
          promise.then(res => addData('fulfilled', res, i), err => addData('rejected', res, i))
        } else {
          addData('fulfilled', res, i)
        }
      })
    })
  }
}